package com.llmcu.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.env.Environment;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

/**
 * xxxx
 *
 * @author liuling
 * @date 2024-10-21 10:03
 */
@RestController
@Slf4j
public class HelloController {
    @Value("${my.name}")
    private String name;
    private final Environment environment;

    public HelloController(Environment environment) {
        this.environment = environment;
    }

    @GetMapping("/config")
    public String getConfig() {
        // -D参数可以读取， -- 参数读取有待验证
        String activeProfile = environment.getProperty("spring.profiles.active");
        String serverPortFromArgs = environment.getProperty("server.port");

        return String.format("User name (from -D): %s, Active Profile (from --): %s, Server Port (from --): %s",
                name, activeProfile, serverPortFromArgs);
    }

    /**
     * 测试`--spring.profiles.active=dev`写在IDEA的什么部分会生效
     */
    @GetMapping("test-application-argument")
    public String testApplicationArgument(){
        return name;
    }

    @GetMapping("hi")
    public String sayHello(){
        log.info("sayHello");
        return "hello2";
    }

    @GetMapping("slow-hi")
    public String saySlowHello() throws InterruptedException {
        log.info("say slowHello");
        TimeUnit.SECONDS.sleep(30);
        return "hello3";
    }

    /**
     * 设置小内存看下，垃圾回收日志会不会打
     *  -Xms128m -Xmx128m -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps
     *
     */
    @GetMapping("trigger-stw")
    public String triggerSTW() throws InterruptedException {

        Thread thread = new Thread(()->{
            // 设置小内存，容易触发 GC
            int[] arr = new int[1000000]; // 使用大数组
            while (true) {
                // 不断创建对象以增加内存压力
                String str = "This is a test string to fill up memory " + System.nanoTime();
                arr = new int[1000000]; // 每次循环都重新分配内存
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        thread.start();

        return "trigger success";
    }



    /**
     * 看下内存溢出日志怎么打
     */
    @GetMapping("trigger-oom")
    public String testOOM(){
        Thread thread = new Thread(()->{
            // 设置小内存，容易触发 GC
            int[] arr = new int[1000000]; // 使用大数组
            List<Object> list = new ArrayList<>();
            while (true) {
                // 不断创建对象以增加内存压力
                String str = "This is a test string to fill up memory " + System.nanoTime();
                arr = new int[1000000]; // 每次循环都重新分配内存
                list.add(arr);
//                try {
//                    TimeUnit.SECONDS.sleep(1);
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
            }
        });
        thread.start();


        return "trigger success";
    }

    /**
     *  尝试OOM让项目停止运行，没有成功
     * @return
     */
    @GetMapping("trigger-oom2")
    public String testOOM2(@RequestParam String param ){
        // 设置小内存，容易触发 GC
        int[] arr = new int[1000000]; // 使用大数组
        List<Object> list = new ArrayList<>();
        while (true) {
            // 不断创建对象以增加内存压力
            String str = "This is a test string to fill up memory " + System.nanoTime();
            arr = new int[1000000]; // 每次循环都重新分配内存
            list.add(arr);
            if("dd".equals(param)){
                break;
            }
        }

        return "trigger success";
    }

    /**
     * 验证tomcat的连接线程数不会影响，项目业务代码中的线程数
     * 同时玩下线程池
     */
    @GetMapping("multi-thread")
    public String multiThread() throws InterruptedException {
        log.info("multi-thread start ==================");
        BlockingQueue blockingQueue = new ArrayBlockingQueue(20);
        ThreadPoolExecutor threadPool = new ThreadPoolExecutor(3,5,10,TimeUnit.MINUTES,blockingQueue);
        // 定义任务数量
        int taskCount = 4;

        // 创建 CompletableFuture 数组
        CompletableFuture<Void>[] futures = new CompletableFuture[taskCount];

        // 提交任务
        for (int i = 0; i < taskCount; i++) {
            futures[i] = CompletableFuture.runAsync(() -> {
                // 模拟随机耗时任务
                // int sleepTime = (int) (Math.random() * 3000); // 随机时间 0-3秒
                int sleepTime = 2;
                try {
                    log.info("[{}] sleeping for [{}] s ",Thread.currentThread().getName(),sleepTime );
                    TimeUnit.SECONDS.sleep(sleepTime);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
                log.info("[{}] finished ",Thread.currentThread().getName());
            }, threadPool);
        }

        // 等待所有任务完成
        CompletableFuture<Void> allOf = CompletableFuture.allOf(futures);

        // 确保所有任务执行完毕
        try {
            allOf.get(); // 等待所有任务完成
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }

        // 关闭线程池
        threadPool.shutdown();
        log.info("multi-thread end ==================");
        return "multi thread success";
    }


    /**
     * 相比多线程的4秒钟，通过sleep实现4秒的耗时操作
     */
    @GetMapping("multi-thread2")
    public String multiThread2() throws InterruptedException {
        log.info("multi-thread2 start ==================");
        TimeUnit.SECONDS.sleep(4);

        log.info("multi-thread end ==================");
        return "multi thread success";
    }

    /**
     * 尝试用java代码方式读取JMX数据，最后因为指标过多，没有那么多时间一一验证而放弃。
     * 如果只看线程数，可以在过滤器中统计
     * 如果想看其他各项指标，应该用JVISUALVM或ARTHAS
     *
     */
    @GetMapping("jmx-query")
    public String queryJmx() throws InterruptedException {
        try {
            JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:12345/jmxrmi");
            JMXConnector jmxConnector = JMXConnectorFactory.connect(url);
            MBeanServerConnection mbsc = jmxConnector.getMBeanServerConnection();

            ObjectName objectName = new ObjectName("Catalina:type=Connector,*");
            for (ObjectName name : mbsc.queryNames(objectName, null)) {
                Integer currentThreadCount = (Integer) mbsc.getAttribute(name, "currentThreadCount");
                Integer currentThreadsBusy = (Integer) mbsc.getAttribute(name, "currentThreadsBusy");
                Integer maxThreads = (Integer) mbsc.getAttribute(name, "maxThreads");

                System.out.println("Connector: " + name.getKeyProperty("name"));
                System.out.println("Current thread count: " + currentThreadCount);
                System.out.println("Current threads busy: " + currentThreadsBusy);
                System.out.println("Max threads: " + maxThreads);
            }
            jmxConnector.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "multi thread success";
    }


}
